1 Introduction

1.1 Install packages, load libraries

We are going to be using a bunch of packages today.

To install all those except tidyverse which you probably already have.

install.packages(c("gghighlight",
                   "gganimate",
                   "patchwork",
                   "ggrepel",
                   "gapminder"))
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.3     ✓ purrr   0.3.4
## ✓ tibble  3.0.6     ✓ dplyr   1.0.4
## ✓ tidyr   1.1.2     ✓ stringr 1.4.0
## ✓ readr   1.4.0     ✓ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(gghighlight) # for bringing attention to certain parts of your plot
library(gganimate) # for animating
library(patchwork) # for making multi-panel plots
library(ggrepel) # for getting labels to not be on top of your points

# data for today
library(gapminder)

1.2 Investigate data

# look at structure
glimpse(gapminder)
## Rows: 1,704
## Columns: 6
## $ country   <fct> Afghanistan, Afghanistan, Afghanistan, Afghanistan, Afghani…
## $ continent <fct> Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia,…
## $ year      <int> 1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997,…
## $ lifeExp   <dbl> 28.801, 30.332, 31.997, 34.020, 36.088, 38.438, 39.854, 40.…
## $ pop       <int> 8425333, 9240934, 10267083, 11537966, 13079460, 14880372, 1…
## $ gdpPercap <dbl> 779.4453, 820.8530, 853.1007, 836.1971, 739.9811, 786.1134,…
head(gapminder)
## # A tibble: 6 x 6
##   country     continent  year lifeExp      pop gdpPercap
##   <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
## 1 Afghanistan Asia       1952    28.8  8425333      779.
## 2 Afghanistan Asia       1957    30.3  9240934      821.
## 3 Afghanistan Asia       1962    32.0 10267083      853.
## 4 Afghanistan Asia       1967    34.0 11537966      836.
## 5 Afghanistan Asia       1972    36.1 13079460      740.
## 6 Afghanistan Asia       1977    38.4 14880372      786.
# what continents do we have?
unique(gapminder$continent)
## [1] Asia     Europe   Africa   Americas Oceania 
## Levels: Africa Americas Asia Europe Oceania

Note, our data is already in tidy-style format.

We will look here just at data from the Americas (North and South America)

# make a df with data only from the Americas
gapminder_americas <- gapminder %>%
  filter(continent == "Americas")

# what countries do we have?
unique(gapminder_americas$country)
##  [1] Argentina           Bolivia             Brazil             
##  [4] Canada              Chile               Colombia           
##  [7] Costa Rica          Cuba                Dominican Republic 
## [10] Ecuador             El Salvador         Guatemala          
## [13] Haiti               Honduras            Jamaica            
## [16] Mexico              Nicaragua           Panama             
## [19] Paraguay            Peru                Puerto Rico        
## [22] Trinidad and Tobago United States       Uruguay            
## [25] Venezuela          
## 142 Levels: Afghanistan Albania Algeria Angola Argentina Australia ... Zimbabwe

1.3 Plot life expectancy over time, for each country

gapminder_americas %>%
  ggplot(aes(x = year, y = lifeExp, group = country, color = country)) +
  geom_line() 

Too crowded to interpret easily.

What if we want to highlight one particular country of interest? Let’s try the United States.

While we are at it, I will add x and y axis labels, a title, subtitle, and caption with labs().

gapminder_americas %>%
  ggplot(aes(x = year, y = lifeExp, group = country, color = country)) +
  geom_line() +
  gghighlight(country == "United States") +
  labs(x = "Year",
       y = "Life Expectancy (years)",
       title = "Life Expectancy in Countries in the Americas",
       subtitle = "From 1952 to 2007",
       caption = "Data from gapminder.org")
## Warning: Tried to calculate with group_by(), but the calculation failed.
## Falling back to ungrouped filter operation...
## label_key: country

1.4 Faceting

What if we want to see all the data at once, but just be able to better attribute each line to the correct country? We can use the [principle of small multiples](https://en.wikipedia.org/wiki/Small_multiple#:~:text=A%20small%20multiple%20(sometimes%20called,was%20popularized%20by%20Edward%20Tufte.), popularized by Edward Tufte, to make a series of charts all on the same scale to allow comparison between them easily.

We can facet using facet_wrap to create small plots for each country. If you want a certain number of rows or columns you can indicate them by including ncol and nrow in the facet_wrap() statement.

gapminder_americas %>%
  ggplot(aes(x = year, y = lifeExp, color = country)) +
  geom_line() +
  facet_wrap(vars(country)) + # facet_wrap(~country) also works
  labs(x = "Year",
       y = "Life Expectancy (years)",
       title = "Life Expectancy in Countries in the Americas",
       subtitle = "From 1952 to 2007",
       caption = "Data from gapminder.org")

Now our legend is not necessary, so let’s remove it. Let’s also remove the gray background since its not really doing much for us. We will also change to theme_minimal() to get rid of the grey background which I don’t think we need.

gapminder_americas %>%
  ggplot(aes(x = year, y = lifeExp)) +
  geom_line(aes(color = country)) +
  theme_minimal() +
  theme(legend.position = "none") +
  facet_wrap(~country) +
  labs(x = "Year",
       y = "Life Expectancy (years)",
       title = "Life Expectancy in Countries in the Americas",
       subtitle = "From 1952 to 2007",
       caption = "Data from gapminder.org")

Wow better! But now its a bit hard to contextualize the line for each country to the whole dataset.

1.5 gghighlight

Let’s bring the rest of data back in, and highlight in each facet the country of interest. We can do this by just adding gghighlight() to our ggplot2 call.

Note: if you want to assign something in R to an object, and then view it, you can put the whole thing in parentheses, without having to call that object back at the end.

(americas_lifeexp <- gapminder_americas %>%
  ggplot(aes(x = year, y = lifeExp)) +
  geom_line(aes(color = country)) +
  gghighlight() +
  theme_minimal() +
  theme(legend.position = "none") +
  facet_wrap(~country) +
  labs(x = "Year",
       y = "Life Expectancy (years)",
       title = "Life Expectancy in Countries in the Americas",
       subtitle = "From 1952 to 2007",
       caption = "Data from gapminder.org"))
## label_key: country
## Too many data series, skip labeling

1.6 Adjusting scales in facet_*

The default in faceting is that the x and y-axes for each plot are all the same. This aids in the interpretation of each small plot in relation to the others, but sometimes you may want freedom to adjust your axes.

For example, if we wanted to plot population over time, if we used the same scale, it would be really hard to see trends within a country.

(americas_pop <- gapminder_americas %>%
  ggplot(aes(x = year, y = pop)) +
  geom_line(aes(color = country)) +
  theme_minimal() +
  theme(legend.position = "none") +
  facet_wrap(~country) +
  labs(x = "Year",
       y = "Population",
       title = "Population in Countries in the Americas",
       subtitle = "From 1952 to 2007",
       caption = "Data from gapminder.org"))

Let’s change the scales so that the y-axis is “free” - i.e., each plot will have an independent y-axis. Note, when you do this, you aren’t really using the principle of small multiples anymore, since the data isn’t all on comparable scales.

gapminder_americas %>%
  ggplot(aes(x = year, y = pop)) +
  geom_line(aes(color = country)) +
  theme_minimal() +
  theme(legend.position = "none") +
  facet_wrap(~country,
             scales = "free_y") +
  labs(x = "Year",
       y = "Population",
       title = "Population of Countries in the Americas",
       subtitle = "From 1952 to 2007",
       caption = "Data from gapminder.org")

The default for scales is "fixed", but you can also set to be "free_x", "free_y", or "free", which means both x and y are free.

1.7 Multi-panel plots

What if I take plots I’ve already made and assemble them together? You can do that simply with the package patchwork().

You can use the syntax: * plot1 + plot2 to get two plots next to each other * plot1 / plot2 to get two plots stacked vertically * plot1 | (plot2 + plot3) to get plot1 in the first row, and plots 2 and 3 in a second row

You can use plot_annotation() to indicate your plots with letters or numbers.

I am going to make some quick plots so we can see how it works. Let’s look at some plots of the United States.

# make df with just United States data
gapminder_usa <- gapminder %>%
  filter(country == "United States")

# make some plots
(usa_lifeexp <- gapminder_usa %>%
  ggplot(aes(x = year, y = lifeExp)) +
  geom_point())

(usa_gdppercap <- gapminder_usa %>%
  ggplot(aes(x = year, y = gdpPercap)) +
  geom_line())

(usa_pop <- gapminder_usa %>%
  ggplot(aes(x = year, y = pop)) +
  geom_col())

Make multi-panel plots. If you need to wrap around a line, make sure you don’t start your line with the +, it won’t work.

(usa_lifeexp + usa_gdppercap) / usa_pop +
plot_annotation(title = "Some plots about the United States",
                  tag_levels = "A")

You can see how this would be really useful for publications!

1.8 Animating

Since we have time-scale data here, we could also build an animation that would help us look at our data. What if we wanted to look at how life expectancy (lifeExp) and population (pop) change over time? We could animate over the variable year, and do this by using the function animate(), and set transition_states() to the variable we are giffing over.

Note, I have included closest_state in the subtitle so the viewer can see what is the year at any stage of the animation.

To be able to tell which dot belongs to which country, I added a geom_text_repel() statement, which labels each point but is smart enough to not let the labels overlap.

I have also set pop to be on a log10 scale.

Note I’ve increased the resolution of the gif by putting it in the curly brackets for this code chunk.

# install.packages("transformr") 
# if you are having problems with gganimate you may need to install transformr

p <- ggplot(gapminder_americas, aes(x = lifeExp, y = pop, fill = country, label = country)) +
  geom_point(shape = 21, color = "black") +
  geom_text_repel() +
  scale_y_log10() +
  theme_classic() +
  theme(legend.position = 'none') +
  labs(title = "Population and Life Expectancy in the Americas",
       subtitle = 'Year: {closest_state}', 
       x = "Life Expectancy", 
       y = "Log10 Population") +
  transition_states(year) 

animate(p)

There are many different ways to transition your data in gganimate - and you can learn more about them here.

1.8.1 Saving my gif

Now I want to save my gif. We can do that simply with the function anim_save() which works a lot like ggsave().

anim_save(filename = "YOUR FILE PATH HERE",
          animation = p)

2 Breakout room exercises

2.1 1. Loading data and get set up

Load the palmerpenguins dataset, look at its structure, and view the beginning of the df.

library(palmerpenguins)
str(penguins)
## tibble [344 × 8] (S3: tbl_df/tbl/data.frame)
##  $ species          : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ island           : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ bill_length_mm   : num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
##  $ bill_depth_mm    : num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
##  $ flipper_length_mm: int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
##  $ body_mass_g      : int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
##  $ sex              : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
##  $ year             : int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...
head(penguins)
## # A tibble: 6 x 8
##   species island bill_length_mm bill_depth_mm flipper_length_… body_mass_g sex  
##   <fct>   <fct>           <dbl>         <dbl>            <int>       <int> <fct>
## 1 Adelie  Torge…           39.1          18.7              181        3750 male 
## 2 Adelie  Torge…           39.5          17.4              186        3800 fema…
## 3 Adelie  Torge…           40.3          18                195        3250 fema…
## 4 Adelie  Torge…           NA            NA                 NA          NA <NA> 
## 5 Adelie  Torge…           36.7          19.3              193        3450 fema…
## 6 Adelie  Torge…           39.3          20.6              190        3650 male 
## # … with 1 more variable: year <int>

2.2 2. Convert bill data from wide to long

Like we did in Code Club 7, convert the two columns about penguin bill dimensions bill_length_mm and bill_depth_mm to two columns called bill_dimension and value. Drop your NAs also. Save this as a new df called penguins_long.

penguins_long <- penguins %>%
  drop_na() %>%
  pivot_longer(cols = bill_length_mm:bill_depth_mm,
               names_to = "bill_dimension",
               values_to = "value_mm",
               names_prefix = "bill_")

head(penguins_long)
## # A tibble: 6 x 8
##   species island flipper_length_… body_mass_g sex    year bill_dimension
##   <fct>   <fct>             <int>       <int> <fct> <int> <chr>         
## 1 Adelie  Torge…              181        3750 male   2007 length_mm     
## 2 Adelie  Torge…              181        3750 male   2007 depth_mm      
## 3 Adelie  Torge…              186        3800 fema…  2007 length_mm     
## 4 Adelie  Torge…              186        3800 fema…  2007 depth_mm      
## 5 Adelie  Torge…              195        3250 fema…  2007 length_mm     
## 6 Adelie  Torge…              195        3250 fema…  2007 depth_mm      
## # … with 1 more variable: value_mm <dbl>

2.4 4. Pretty up your plot

You can do things like change your axis labels, add title, change themes as you see fit. Color your points by sex.

library(hrbrthemes) # for pretty & easy themes

# formatting facet strip text labels
dim_mm <- c("Culman Bill Depth", "Culman Bill Length")
names(dim_mm) <- c("depth_mm", "length_mm")

# this is just one example
penguins_long %>%
  ggplot(aes(x = body_mass_g, y = value_mm, color = sex)) +
  geom_point() +
  theme_ipsum_rc() +
  theme(axis.title.x = element_text(hjust = 0.5),
        axis.title.y = element_text(hjust = 0.5),
        strip.text = element_text(hjust = 0.5)) +
  labs(x = "Body Mass (g)",
       y = "mm",
       title = "Bill length and depth vs. body mass in penguins",
       color = "Sex",
       caption = "Data from https://allisonhorst.github.io/palmerpenguins/") +
  facet_wrap(vars(bill_dimension),
             labeller = labeller(bill_dimension = dim_mm))

2.5 5. Add a second dimension of faceting by species

penguins_long %>%
  ggplot(aes(x = body_mass_g, y = value_mm, color = sex)) +
  geom_point() +
  theme_ipsum_rc() +
  theme(axis.title.x = element_text(hjust = 0.5),
        axis.title.y = element_text(hjust = 0.5),
        strip.text = element_text(hjust = 0.5)) +
  labs(x = "Body Mass (g)",
       y = "mm",
       title = "Bill length and depth vs. body mass in penguins",
       color = "Sex",
       caption = "Data from https://allisonhorst.github.io/palmerpenguins/") +
  facet_wrap(bill_dimension~species,
             labeller = labeller(bill_dimension = dim_mm))

2.6 6. Take your plot from 3 and highlight

Using your plot from Exercise 3, highlight the datapoints coming from Dream Island in purple.

unique(penguins_long$island)
## [1] Torgersen Biscoe    Dream    
## Levels: Biscoe Dream Torgersen
penguins_long %>%
  ggplot(aes(x = body_mass_g, y = value_mm)) +
  geom_point(color = "purple") +
  gghighlight(island == "Dream") +
  facet_wrap(vars(bill_dimension))

2.7 7. Highlight little penguins

Using your sample plot for Exercise 3, highlight penguins that have a body_mass_g less than 3500 g, in blue.

penguins_long %>%
  ggplot(aes(x = body_mass_g, y = value_mm)) +
  geom_point(color = "blue") +
  gghighlight(body_mass_g < 3500) +
  facet_wrap(vars(bill_dimension))

3 Bonus exercises

3.1 1. Animating

Plot flipper_length_mm vs. body_mass_g and animate the plot to show only one species at a time.

flipper_by_BW <- penguins %>%
  ggplot(aes(x = body_mass_g, y = flipper_length_mm, fill = species)) +
  geom_point(shape = 21, color = "black") +
  theme_classic() +
  theme(legend.position = 'none') +
  labs(title = "Population and Life Expectancy in the Americas",
       subtitle = 'Penguin Species: {closest_state}', 
       x = "Body Mass (g)", 
       y = "Flipper Length (mm)") +
  transition_states(species) 

animate(flipper_by_BW)

3.2 2. Save your gif

anim_save(filename = "YOUR FILE PATH HERE",
          animation = flipper_by_BW)

3.3 3. Multi-panel plots

We are making a few plots to assemble a multi-panel plot. Let’s remember what data we’re working for.

head(penguins_long)
## # A tibble: 6 x 8
##   species island flipper_length_… body_mass_g sex    year bill_dimension
##   <fct>   <fct>             <int>       <int> <fct> <int> <chr>         
## 1 Adelie  Torge…              181        3750 male   2007 length_mm     
## 2 Adelie  Torge…              181        3750 male   2007 depth_mm      
## 3 Adelie  Torge…              186        3800 fema…  2007 length_mm     
## 4 Adelie  Torge…              186        3800 fema…  2007 depth_mm      
## 5 Adelie  Torge…              195        3250 fema…  2007 length_mm     
## 6 Adelie  Torge…              195        3250 fema…  2007 depth_mm      
## # … with 1 more variable: value_mm <dbl>

Boxplot of body_mass_g by sex.

penguins_mass_by_sex <- penguins_long %>%
  ggplot(aes(x = sex, y = body_mass_g)) +
  geom_boxplot()

penguins_mass_by_sex

Histogram of number of observations per island.

penguins_by_island <- penguins_long %>%
  ggplot(aes(y = island, fill = island)) +
  geom_histogram(stat = "count")
## Warning: Ignoring unknown parameters: binwidth, bins, pad
penguins_by_island

Distribution of flipper_length_mm by species.

penguins_flipper_species <- penguins_long %>%
  ggplot(aes(x = flipper_length_mm, group = species, fill = species)) +
  geom_density(alpha = 0.5) +
  scale_fill_viridis_d()

penguins_flipper_species

Assemble multi-plot figure using the plots you just made.

penguins_flipper_species / (penguins_mass_by_sex + penguins_by_island) +
  plot_annotation(title = "Looking at penguins...",
                  tag_levels = "A")

LS0tCnRpdGxlOiAiRmFjZXRpbmcsIGFuaW1hdGluZywgYW5kIG11bHRpLXBhbmVsIGZpZ3VyZXMiCmF1dGhvcjogIllvdSEiCmRhdGU6ICIyLzEyLzIwMjEiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRoZW1lOiBmbGF0bHkKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCiMjIEluc3RhbGwgcGFja2FnZXMsIGxvYWQgbGlicmFyaWVzCldlIGFyZSBnb2luZyB0byBiZSB1c2luZyBhIGJ1bmNoIG9mIHBhY2thZ2VzIHRvZGF5LgoKVG8gaW5zdGFsbCBhbGwgdGhvc2UgZXhjZXB0IHRpZHl2ZXJzZSB3aGljaCB5b3UgcHJvYmFibHkgYWxyZWFkeSBoYXZlLgpgYGB7ciwgZXZhbCA9IEZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKGMoImdnaGlnaGxpZ2h0IiwKICAgICAgICAgICAgICAgICAgICJnZ2FuaW1hdGUiLAogICAgICAgICAgICAgICAgICAgInBhdGNod29yayIsCiAgICAgICAgICAgICAgICAgICAiZ2dyZXBlbCIsCiAgICAgICAgICAgICAgICAgICAiZ2FwbWluZGVyIikpCmBgYAoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdnaGlnaGxpZ2h0KSAjIGZvciBicmluZ2luZyBhdHRlbnRpb24gdG8gY2VydGFpbiBwYXJ0cyBvZiB5b3VyIHBsb3QKbGlicmFyeShnZ2FuaW1hdGUpICMgZm9yIGFuaW1hdGluZwpsaWJyYXJ5KHBhdGNod29yaykgIyBmb3IgbWFraW5nIG11bHRpLXBhbmVsIHBsb3RzCmxpYnJhcnkoZ2dyZXBlbCkgIyBmb3IgZ2V0dGluZyBsYWJlbHMgdG8gbm90IGJlIG9uIHRvcCBvZiB5b3VyIHBvaW50cwoKIyBkYXRhIGZvciB0b2RheQpsaWJyYXJ5KGdhcG1pbmRlcikKYGBgCgojIyBJbnZlc3RpZ2F0ZSBkYXRhCgpgYGB7cn0KIyBsb29rIGF0IHN0cnVjdHVyZQpnbGltcHNlKGdhcG1pbmRlcikKaGVhZChnYXBtaW5kZXIpCgojIHdoYXQgY29udGluZW50cyBkbyB3ZSBoYXZlPwp1bmlxdWUoZ2FwbWluZGVyJGNvbnRpbmVudCkKYGBgCgoqTm90ZSwgb3VyIGRhdGEgaXMgYWxyZWFkeSBpbiB0aWR5LXN0eWxlIGZvcm1hdC4qICAKCldlIHdpbGwgbG9vayBoZXJlIGp1c3QgYXQgZGF0YSBmcm9tIHRoZSBBbWVyaWNhcyAoTm9ydGggYW5kIFNvdXRoIEFtZXJpY2EpCmBgYHtyfQojIG1ha2UgYSBkZiB3aXRoIGRhdGEgb25seSBmcm9tIHRoZSBBbWVyaWNhcwpnYXBtaW5kZXJfYW1lcmljYXMgPC0gZ2FwbWluZGVyICU+JQogIGZpbHRlcihjb250aW5lbnQgPT0gIkFtZXJpY2FzIikKCiMgd2hhdCBjb3VudHJpZXMgZG8gd2UgaGF2ZT8KdW5pcXVlKGdhcG1pbmRlcl9hbWVyaWNhcyRjb3VudHJ5KQpgYGAKCiMjIFBsb3QgbGlmZSBleHBlY3RhbmN5IG92ZXIgdGltZSwgZm9yIGVhY2ggY291bnRyeQpgYGB7cn0KZ2FwbWluZGVyX2FtZXJpY2FzICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBsaWZlRXhwLCBncm91cCA9IGNvdW50cnksIGNvbG9yID0gY291bnRyeSkpICsKICBnZW9tX2xpbmUoKSAKYGBgCgpUb28gY3Jvd2RlZCB0byBpbnRlcnByZXQgZWFzaWx5LgoKV2hhdCBpZiB3ZSB3YW50IHRvIGhpZ2hsaWdodCBvbmUgcGFydGljdWxhciBjb3VudHJ5IG9mIGludGVyZXN0PyAgTGV0J3MgdHJ5IHRoZSBVbml0ZWQgU3RhdGVzLiAgCgpXaGlsZSB3ZSBhcmUgYXQgaXQsIEkgd2lsbCBhZGQgeCBhbmQgeSBheGlzIGxhYmVscywgYSB0aXRsZSwgc3VidGl0bGUsIGFuZCBjYXB0aW9uIHdpdGggW2BsYWJzKClgXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvbGFicy5odG1sKS4gIApgYGB7cn0KZ2FwbWluZGVyX2FtZXJpY2FzICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBsaWZlRXhwLCBncm91cCA9IGNvdW50cnksIGNvbG9yID0gY291bnRyeSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2doaWdobGlnaHQoY291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyIpICsKICBsYWJzKHggPSAiWWVhciIsCiAgICAgICB5ID0gIkxpZmUgRXhwZWN0YW5jeSAoeWVhcnMpIiwKICAgICAgIHRpdGxlID0gIkxpZmUgRXhwZWN0YW5jeSBpbiBDb3VudHJpZXMgaW4gdGhlIEFtZXJpY2FzIiwKICAgICAgIHN1YnRpdGxlID0gIkZyb20gMTk1MiB0byAyMDA3IiwKICAgICAgIGNhcHRpb24gPSAiRGF0YSBmcm9tIGdhcG1pbmRlci5vcmciKQpgYGAKCiMjIEZhY2V0aW5nCldoYXQgaWYgd2Ugd2FudCB0byBzZWUgYWxsIHRoZSBkYXRhIGF0IG9uY2UsIGJ1dCBqdXN0IGJlIGFibGUgdG8gYmV0dGVyIGF0dHJpYnV0ZSBlYWNoIGxpbmUgdG8gdGhlIGNvcnJlY3QgY291bnRyeT8gIFdlIGNhbiB1c2UgdGhlIFtwcmluY2lwbGUgb2Ygc21hbGwgbXVsdGlwbGVzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TbWFsbF9tdWx0aXBsZSM6fjp0ZXh0PUElMjBzbWFsbCUyMG11bHRpcGxlJTIwKHNvbWV0aW1lcyUyMGNhbGxlZCx3YXMlMjBwb3B1bGFyaXplZCUyMGJ5JTIwRWR3YXJkJTIwVHVmdGUuKSwgcG9wdWxhcml6ZWQgYnkgRWR3YXJkIFR1ZnRlLCB0byBtYWtlIGEgc2VyaWVzIG9mIGNoYXJ0cyBhbGwgb24gdGhlIHNhbWUgc2NhbGUgdG8gYWxsb3cgY29tcGFyaXNvbiBiZXR3ZWVuIHRoZW0gZWFzaWx5LiAKCldlIGNhbiBmYWNldCB1c2luZyBbYGZhY2V0X3dyYXBgXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZmFjZXRfd3JhcC5odG1sKSB0byBjcmVhdGUgc21hbGwgcGxvdHMgZm9yIGVhY2ggY291bnRyeS4gIElmIHlvdSB3YW50IGEgY2VydGFpbiBudW1iZXIgb2Ygcm93cyBvciBjb2x1bW5zIHlvdSBjYW4gaW5kaWNhdGUgdGhlbSBieSBpbmNsdWRpbmcgYG5jb2xgIGFuZCBgbnJvd2AgaW4gdGhlIGBmYWNldF93cmFwKClgIHN0YXRlbWVudC4KCmBgYHtyLCBmaWcud2lkdGggPSAxNCwgZmlnLmhlaWdodCA9IDh9CmdhcG1pbmRlcl9hbWVyaWNhcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gbGlmZUV4cCwgY29sb3IgPSBjb3VudHJ5KSkgKwogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKHZhcnMoY291bnRyeSkpICsgIyBmYWNldF93cmFwKH5jb3VudHJ5KSBhbHNvIHdvcmtzCiAgbGFicyh4ID0gIlllYXIiLAogICAgICAgeSA9ICJMaWZlIEV4cGVjdGFuY3kgKHllYXJzKSIsCiAgICAgICB0aXRsZSA9ICJMaWZlIEV4cGVjdGFuY3kgaW4gQ291bnRyaWVzIGluIHRoZSBBbWVyaWNhcyIsCiAgICAgICBzdWJ0aXRsZSA9ICJGcm9tIDE5NTIgdG8gMjAwNyIsCiAgICAgICBjYXB0aW9uID0gIkRhdGEgZnJvbSBnYXBtaW5kZXIub3JnIikKYGBgCgpOb3cgb3VyIGxlZ2VuZCBpcyBub3QgbmVjZXNzYXJ5LCBzbyBsZXQncyByZW1vdmUgaXQuICBMZXQncyBhbHNvIHJlbW92ZSB0aGUgZ3JheSBiYWNrZ3JvdW5kIHNpbmNlIGl0cyBub3QgcmVhbGx5IGRvaW5nIG11Y2ggZm9yIHVzLiAgV2Ugd2lsbCBhbHNvIGNoYW5nZSB0byBgdGhlbWVfbWluaW1hbCgpYCB0byBnZXQgcmlkIG9mIHRoZSBncmV5IGJhY2tncm91bmQgd2hpY2ggSSBkb24ndCB0aGluayB3ZSBuZWVkLgpgYGB7ciwgZmlnLndpZHRoID0gMTQsIGZpZy5oZWlnaHQgPSA4fQpnYXBtaW5kZXJfYW1lcmljYXMgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHApKSArCiAgZ2VvbV9saW5lKGFlcyhjb2xvciA9IGNvdW50cnkpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBmYWNldF93cmFwKH5jb3VudHJ5KSArCiAgbGFicyh4ID0gIlllYXIiLAogICAgICAgeSA9ICJMaWZlIEV4cGVjdGFuY3kgKHllYXJzKSIsCiAgICAgICB0aXRsZSA9ICJMaWZlIEV4cGVjdGFuY3kgaW4gQ291bnRyaWVzIGluIHRoZSBBbWVyaWNhcyIsCiAgICAgICBzdWJ0aXRsZSA9ICJGcm9tIDE5NTIgdG8gMjAwNyIsCiAgICAgICBjYXB0aW9uID0gIkRhdGEgZnJvbSBnYXBtaW5kZXIub3JnIikKYGBgCgpXb3cgYmV0dGVyISAgQnV0IG5vdyBpdHMgYSBiaXQgaGFyZCB0byBjb250ZXh0dWFsaXplIHRoZSBsaW5lIGZvciBlYWNoIGNvdW50cnkgdG8gdGhlIHdob2xlIGRhdGFzZXQuICAKCiMjIGdnaGlnaGxpZ2h0CkxldCdzIGJyaW5nIHRoZSByZXN0IG9mIGRhdGEgYmFjayBpbiwgYW5kIGhpZ2hsaWdodCBpbiBlYWNoIGZhY2V0IHRoZSBjb3VudHJ5IG9mIGludGVyZXN0LiAgV2UgY2FuIGRvIHRoaXMgYnkganVzdCBhZGRpbmcgYGdnaGlnaGxpZ2h0KClgIHRvIG91ciBgZ2dwbG90MmAgY2FsbC4KCk5vdGU6IGlmIHlvdSB3YW50IHRvIGFzc2lnbiBzb21ldGhpbmcgaW4gUiB0byBhbiBvYmplY3QsIGFuZCB0aGVuIHZpZXcgaXQsIHlvdSBjYW4gcHV0IHRoZSB3aG9sZSB0aGluZyBpbiBwYXJlbnRoZXNlcywgd2l0aG91dCBoYXZpbmcgdG8gY2FsbCB0aGF0IG9iamVjdCBiYWNrIGF0IHRoZSBlbmQuCmBgYHtyLCBmaWcud2lkdGggPSAxNCwgZmlnLmhlaWdodCA9IDh9CihhbWVyaWNhc19saWZlZXhwIDwtIGdhcG1pbmRlcl9hbWVyaWNhcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gbGlmZUV4cCkpICsKICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gY291bnRyeSkpICsKICBnZ2hpZ2hsaWdodCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGZhY2V0X3dyYXAofmNvdW50cnkpICsKICBsYWJzKHggPSAiWWVhciIsCiAgICAgICB5ID0gIkxpZmUgRXhwZWN0YW5jeSAoeWVhcnMpIiwKICAgICAgIHRpdGxlID0gIkxpZmUgRXhwZWN0YW5jeSBpbiBDb3VudHJpZXMgaW4gdGhlIEFtZXJpY2FzIiwKICAgICAgIHN1YnRpdGxlID0gIkZyb20gMTk1MiB0byAyMDA3IiwKICAgICAgIGNhcHRpb24gPSAiRGF0YSBmcm9tIGdhcG1pbmRlci5vcmciKSkKYGBgCgojIyBBZGp1c3Rpbmcgc2NhbGVzIGluIGBmYWNldF8qYApUaGUgZGVmYXVsdCBpbiBmYWNldGluZyBpcyB0aGF0IHRoZSB4IGFuZCB5LWF4ZXMgZm9yIGVhY2ggcGxvdCBhcmUgYWxsIHRoZSBzYW1lLiAgVGhpcyBhaWRzIGluIHRoZSBpbnRlcnByZXRhdGlvbiBvZiBlYWNoIHNtYWxsIHBsb3QgaW4gcmVsYXRpb24gdG8gdGhlIG90aGVycywgYnV0IHNvbWV0aW1lcyB5b3UgbWF5IHdhbnQgZnJlZWRvbSB0byBhZGp1c3QgeW91ciBheGVzLgoKRm9yIGV4YW1wbGUsIGlmIHdlIHdhbnRlZCB0byBwbG90IHBvcHVsYXRpb24gb3ZlciB0aW1lLCBpZiB3ZSB1c2VkIHRoZSBzYW1lIHNjYWxlLCBpdCB3b3VsZCBiZSByZWFsbHkgaGFyZCB0byBzZWUgdHJlbmRzIHdpdGhpbiBhIGNvdW50cnkuCgpgYGB7cn0KKGFtZXJpY2FzX3BvcCA8LSBnYXBtaW5kZXJfYW1lcmljYXMgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHBvcCkpICsKICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gY291bnRyeSkpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGZhY2V0X3dyYXAofmNvdW50cnkpICsKICBsYWJzKHggPSAiWWVhciIsCiAgICAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgICAgdGl0bGUgPSAiUG9wdWxhdGlvbiBpbiBDb3VudHJpZXMgaW4gdGhlIEFtZXJpY2FzIiwKICAgICAgIHN1YnRpdGxlID0gIkZyb20gMTk1MiB0byAyMDA3IiwKICAgICAgIGNhcHRpb24gPSAiRGF0YSBmcm9tIGdhcG1pbmRlci5vcmciKSkKYGBgCgpMZXQncyBjaGFuZ2UgdGhlIHNjYWxlcyBzbyB0aGF0IHRoZSB5LWF4aXMgaXMgImZyZWUiIC0gaS5lLiwgZWFjaCBwbG90IHdpbGwgaGF2ZSBhbiBpbmRlcGVuZGVudCB5LWF4aXMuICBOb3RlLCB3aGVuIHlvdSBkbyB0aGlzLCB5b3UgYXJlbid0IHJlYWxseSB1c2luZyB0aGUgcHJpbmNpcGxlIG9mIHNtYWxsIG11bHRpcGxlcyBhbnltb3JlLCBzaW5jZSB0aGUgZGF0YSBpc24ndCBhbGwgb24gY29tcGFyYWJsZSBzY2FsZXMuCmBgYHtyLCBmaWcud2lkdGggPSAxNCwgZmlnLmhlaWdodCA9IDh9CmdhcG1pbmRlcl9hbWVyaWNhcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gcG9wKSkgKwogIGdlb21fbGluZShhZXMoY29sb3IgPSBjb3VudHJ5KSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZmFjZXRfd3JhcCh+Y291bnRyeSwKICAgICAgICAgICAgIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgbGFicyh4ID0gIlllYXIiLAogICAgICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgICAgIHRpdGxlID0gIlBvcHVsYXRpb24gb2YgQ291bnRyaWVzIGluIHRoZSBBbWVyaWNhcyIsCiAgICAgICBzdWJ0aXRsZSA9ICJGcm9tIDE5NTIgdG8gMjAwNyIsCiAgICAgICBjYXB0aW9uID0gIkRhdGEgZnJvbSBnYXBtaW5kZXIub3JnIikKYGBgCgpUaGUgZGVmYXVsdCBmb3IgYHNjYWxlc2AgaXMgYCJmaXhlZCJgLCBidXQgeW91IGNhbiBhbHNvIHNldCB0byBiZSBgImZyZWVfeCJgLCBgImZyZWVfeSJgLCBvciBgImZyZWUiYCwgd2hpY2ggbWVhbnMgYm90aCB4IGFuZCB5IGFyZSBmcmVlLgoKIyMgTXVsdGktcGFuZWwgcGxvdHMKV2hhdCBpZiBJIHRha2UgcGxvdHMgSSd2ZSBhbHJlYWR5IG1hZGUgYW5kIGFzc2VtYmxlIHRoZW0gdG9nZXRoZXI/ICBZb3UgY2FuIGRvIHRoYXQgc2ltcGx5IHdpdGggdGhlIHBhY2thZ2UgW2BwYXRjaHdvcmsoKWBdKGh0dHBzOi8vcGF0Y2h3b3JrLmRhdGEtaW1hZ2luaXN0LmNvbS8pLgoKWW91IGNhbiB1c2UgdGhlIHN5bnRheDoKKiBgcGxvdDEgKyBwbG90MmAgdG8gZ2V0IHR3byBwbG90cyBuZXh0IHRvIGVhY2ggb3RoZXIKKiBgcGxvdDEgLyBwbG90MmAgdG8gZ2V0IHR3byBwbG90cyBzdGFja2VkIHZlcnRpY2FsbHkKKiBgcGxvdDEgfCAocGxvdDIgKyBwbG90MylgIHRvIGdldCBwbG90MSBpbiB0aGUgZmlyc3Qgcm93LCBhbmQgcGxvdHMgMiBhbmQgMyBpbiBhIHNlY29uZCByb3cKCllvdSBjYW4gdXNlIFtgcGxvdF9hbm5vdGF0aW9uKClgXShodHRwczovL3BhdGNod29yay5kYXRhLWltYWdpbmlzdC5jb20vcmVmZXJlbmNlL3Bsb3RfYW5ub3RhdGlvbi5odG1sKSB0byBpbmRpY2F0ZSB5b3VyIHBsb3RzIHdpdGggbGV0dGVycyBvciBudW1iZXJzLgoKSSBhbSBnb2luZyB0byBtYWtlIHNvbWUgcXVpY2sgcGxvdHMgc28gd2UgY2FuIHNlZSBob3cgaXQgd29ya3MuICBMZXQncyBsb29rIGF0IHNvbWUgcGxvdHMgb2YgdGhlIFVuaXRlZCBTdGF0ZXMuCgpgYGB7cn0KIyBtYWtlIGRmIHdpdGgganVzdCBVbml0ZWQgU3RhdGVzIGRhdGEKZ2FwbWluZGVyX3VzYSA8LSBnYXBtaW5kZXIgJT4lCiAgZmlsdGVyKGNvdW50cnkgPT0gIlVuaXRlZCBTdGF0ZXMiKQoKIyBtYWtlIHNvbWUgcGxvdHMKKHVzYV9saWZlZXhwIDwtIGdhcG1pbmRlcl91c2EgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHApKSArCiAgZ2VvbV9wb2ludCgpKQoKKHVzYV9nZHBwZXJjYXAgPC0gZ2FwbWluZGVyX3VzYSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gZ2RwUGVyY2FwKSkgKwogIGdlb21fbGluZSgpKQoKKHVzYV9wb3AgPC0gZ2FwbWluZGVyX3VzYSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gcG9wKSkgKwogIGdlb21fY29sKCkpCmBgYAoKTWFrZSBtdWx0aS1wYW5lbCBwbG90cy4gIElmIHlvdSBuZWVkIHRvIHdyYXAgYXJvdW5kIGEgbGluZSwgbWFrZSBzdXJlIHlvdSBkb24ndCBzdGFydCB5b3VyIGxpbmUgd2l0aCB0aGUgKywgaXQgd29uJ3Qgd29yay4KYGBge3J9Cih1c2FfbGlmZWV4cCArIHVzYV9nZHBwZXJjYXApIC8gdXNhX3BvcCArCnBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJTb21lIHBsb3RzIGFib3V0IHRoZSBVbml0ZWQgU3RhdGVzIiwKICAgICAgICAgICAgICAgICAgdGFnX2xldmVscyA9ICJBIikKYGBgCgpZb3UgY2FuIHNlZSBob3cgdGhpcyB3b3VsZCBiZSByZWFsbHkgdXNlZnVsIGZvciBwdWJsaWNhdGlvbnMhCgojIyBBbmltYXRpbmcKU2luY2Ugd2UgaGF2ZSB0aW1lLXNjYWxlIGRhdGEgaGVyZSwgd2UgY291bGQgYWxzbyBidWlsZCBhbiBhbmltYXRpb24gdGhhdCB3b3VsZCBoZWxwIHVzIGxvb2sgYXQgb3VyIGRhdGEuICBXaGF0IGlmIHdlIHdhbnRlZCB0byBsb29rIGF0IGhvdyBsaWZlIGV4cGVjdGFuY3kgKGBsaWZlRXhwYCkgYW5kIHBvcHVsYXRpb24gKGBwb3BgKSBjaGFuZ2Ugb3ZlciB0aW1lPyAgV2UgY291bGQgYW5pbWF0ZSBvdmVyIHRoZSB2YXJpYWJsZSBgeWVhcmAsIGFuZCBkbyB0aGlzIGJ5IHVzaW5nIHRoZSBmdW5jdGlvbiBbYGFuaW1hdGUoKWBdKGh0dHBzOi8vZ2dhbmltYXRlLmNvbS9yZWZlcmVuY2UvYW5pbWF0ZS5odG1sKSwgYW5kIHNldCBbYHRyYW5zaXRpb25fc3RhdGVzKClgXShodHRwczovL2dnYW5pbWF0ZS5jb20vcmVmZXJlbmNlL3RyYW5zaXRpb25fc3RhdGVzLmh0bWwpIHRvIHRoZSB2YXJpYWJsZSB3ZSBhcmUgZ2lmZmluZyBvdmVyLiAgCgpOb3RlLCBJIGhhdmUgaW5jbHVkZWQgYGNsb3Nlc3Rfc3RhdGVgIGluIHRoZSBzdWJ0aXRsZSBzbyB0aGUgdmlld2VyIGNhbiBzZWUgd2hhdCBpcyB0aGUgeWVhciBhdCBhbnkgc3RhZ2Ugb2YgdGhlIGFuaW1hdGlvbi4KClRvIGJlIGFibGUgdG8gdGVsbCB3aGljaCBkb3QgYmVsb25ncyB0byB3aGljaCBjb3VudHJ5LCBJIGFkZGVkIGEgW2BnZW9tX3RleHRfcmVwZWwoKWBdKGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9nZ3JlcGVsL3ZlcnNpb25zLzAuOS4xL3RvcGljcy9nZW9tX2xhYmVsX3JlcGVsKSBzdGF0ZW1lbnQsIHdoaWNoIGxhYmVscyBlYWNoIHBvaW50IGJ1dCBpcyBzbWFydCBlbm91Z2ggdG8gbm90IGxldCB0aGUgbGFiZWxzIG92ZXJsYXAuCgpJIGhhdmUgYWxzbyBzZXQgYHBvcGAgdG8gYmUgb24gYSBsb2cxMCBzY2FsZS4KCk5vdGUgSSd2ZSBpbmNyZWFzZWQgdGhlIHJlc29sdXRpb24gb2YgdGhlIGdpZiBieSBwdXR0aW5nIGl0IGluIHRoZSBjdXJseSBicmFja2V0cyBmb3IgdGhpcyBjb2RlIGNodW5rLgoKYGBge3IsIGNhY2hlID0gVFJVRSwgZHBpID0gNjAwfQojIGluc3RhbGwucGFja2FnZXMoInRyYW5zZm9ybXIiKSAKIyBpZiB5b3UgYXJlIGhhdmluZyBwcm9ibGVtcyB3aXRoIGdnYW5pbWF0ZSB5b3UgbWF5IG5lZWQgdG8gaW5zdGFsbCB0cmFuc2Zvcm1yCgpwIDwtIGdncGxvdChnYXBtaW5kZXJfYW1lcmljYXMsIGFlcyh4ID0gbGlmZUV4cCwgeSA9IHBvcCwgZmlsbCA9IGNvdW50cnksIGxhYmVsID0gY291bnRyeSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fdGV4dF9yZXBlbCgpICsKICBzY2FsZV95X2xvZzEwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKSArCiAgbGFicyh0aXRsZSA9ICJQb3B1bGF0aW9uIGFuZCBMaWZlIEV4cGVjdGFuY3kgaW4gdGhlIEFtZXJpY2FzIiwKICAgICAgIHN1YnRpdGxlID0gJ1llYXI6IHtjbG9zZXN0X3N0YXRlfScsIAogICAgICAgeCA9ICJMaWZlIEV4cGVjdGFuY3kiLCAKICAgICAgIHkgPSAiTG9nMTAgUG9wdWxhdGlvbiIpICsKICB0cmFuc2l0aW9uX3N0YXRlcyh5ZWFyKSAKCmFuaW1hdGUocCkKYGBgCgpUaGVyZSBhcmUgbWFueSBkaWZmZXJlbnQgd2F5cyB0byB0cmFuc2l0aW9uIHlvdXIgZGF0YSBpbiBgZ2dhbmltYXRlYCAtIGFuZCB5b3UgY2FuIGxlYXJuIG1vcmUgYWJvdXQgdGhlbSBbaGVyZV0oaHR0cHM6Ly9nZ2FuaW1hdGUuY29tL3JlZmVyZW5jZS9pbmRleC5odG1sKS4KCiMjIyBTYXZpbmcgbXkgZ2lmCk5vdyBJIHdhbnQgdG8gc2F2ZSBteSBnaWYuICBXZSBjYW4gZG8gdGhhdCBzaW1wbHkgd2l0aCB0aGUgZnVuY3Rpb24gW2BhbmltX3NhdmUoKWBdKGh0dHBzOi8vZ2dhbmltYXRlLmNvbS9yZWZlcmVuY2UvYW5pbV9zYXZlLmh0bWwpIHdoaWNoIHdvcmtzIGEgbG90IGxpa2UgYGdnc2F2ZSgpYC4gIAoKYGBge3IsIGV2YWwgPSBGQUxTRX0KYW5pbV9zYXZlKGZpbGVuYW1lID0gIllPVVIgRklMRSBQQVRIIEhFUkUiLAogICAgICAgICAgYW5pbWF0aW9uID0gcCkKYGBgCgojIEJyZWFrb3V0IHJvb20gZXhlcmNpc2VzCgojIyAxLiBMb2FkaW5nIGRhdGEgYW5kIGdldCBzZXQgdXAKTG9hZCB0aGUgYHBhbG1lcnBlbmd1aW5zYCBkYXRhc2V0LCBsb29rIGF0IGl0cyBzdHJ1Y3R1cmUsIGFuZCB2aWV3IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGRmLgpgYGB7cn0KbGlicmFyeShwYWxtZXJwZW5ndWlucykKc3RyKHBlbmd1aW5zKQpoZWFkKHBlbmd1aW5zKQpgYGAKCiMjIDIuIENvbnZlcnQgYmlsbCBkYXRhIGZyb20gd2lkZSB0byBsb25nCkxpa2Ugd2UgZGlkIGluIFtDb2RlIENsdWIgN10oaHR0cHM6Ly9iaW9kYXNoLmdpdGh1Yi5pby9jb2RlY2x1Yi8wOF9waXZvdGluZy8pLCBjb252ZXJ0IHRoZSB0d28gY29sdW1ucyBhYm91dCBwZW5ndWluIGJpbGwgZGltZW5zaW9ucyBgYmlsbF9sZW5ndGhfbW1gIGFuZCBgYmlsbF9kZXB0aF9tbWAgdG8gdHdvIGNvbHVtbnMgY2FsbGVkIGBiaWxsX2RpbWVuc2lvbmAgYW5kIGB2YWx1ZWAuICBEcm9wIHlvdXIgTkFzIGFsc28uICBTYXZlIHRoaXMgYXMgYSBuZXcgZGYgY2FsbGVkIGBwZW5ndWluc19sb25nYC4KYGBge3J9CnBlbmd1aW5zX2xvbmcgPC0gcGVuZ3VpbnMgJT4lCiAgZHJvcF9uYSgpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYmlsbF9sZW5ndGhfbW06YmlsbF9kZXB0aF9tbSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiYmlsbF9kaW1lbnNpb24iLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWVfbW0iLAogICAgICAgICAgICAgICBuYW1lc19wcmVmaXggPSAiYmlsbF8iKQoKaGVhZChwZW5ndWluc19sb25nKQpgYGAKCiMjIDMuIFBsb3QgYm9keSBtYXNzIGFzIHJlbGF0ZWQgdG8gYmlsbCBsZW5ndGggYW5kIGRlcHRoCmBgYHtyfQpwZW5ndWluc19sb25nICU+JQogIGdncGxvdChhZXMoeCA9IGJvZHlfbWFzc19nLCB5ID0gdmFsdWVfbW0pKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF93cmFwKHZhcnMoYmlsbF9kaW1lbnNpb24pKQpgYGAKCiMjIDQuIFByZXR0eSB1cCB5b3VyIHBsb3QKWW91IGNhbiBkbyB0aGluZ3MgbGlrZSBjaGFuZ2UgeW91ciBheGlzIGxhYmVscywgYWRkIHRpdGxlLCBjaGFuZ2UgdGhlbWVzIGFzIHlvdSBzZWUgZml0LiAgQ29sb3IgeW91ciBwb2ludHMgYnkgc2V4LgpgYGB7cn0KbGlicmFyeShocmJydGhlbWVzKSAjIGZvciBwcmV0dHkgJiBlYXN5IHRoZW1lcwoKIyBmb3JtYXR0aW5nIGZhY2V0IHN0cmlwIHRleHQgbGFiZWxzCmRpbV9tbSA8LSBjKCJDdWxtYW4gQmlsbCBEZXB0aCIsICJDdWxtYW4gQmlsbCBMZW5ndGgiKQpuYW1lcyhkaW1fbW0pIDwtIGMoImRlcHRoX21tIiwgImxlbmd0aF9tbSIpCgojIHRoaXMgaXMganVzdCBvbmUgZXhhbXBsZQpwZW5ndWluc19sb25nICU+JQogIGdncGxvdChhZXMoeCA9IGJvZHlfbWFzc19nLCB5ID0gdmFsdWVfbW0sIGNvbG9yID0gc2V4KSkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfaXBzdW1fcmMoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgbGFicyh4ID0gIkJvZHkgTWFzcyAoZykiLAogICAgICAgeSA9ICJtbSIsCiAgICAgICB0aXRsZSA9ICJCaWxsIGxlbmd0aCBhbmQgZGVwdGggdnMuIGJvZHkgbWFzcyBpbiBwZW5ndWlucyIsCiAgICAgICBjb2xvciA9ICJTZXgiLAogICAgICAgY2FwdGlvbiA9ICJEYXRhIGZyb20gaHR0cHM6Ly9hbGxpc29uaG9yc3QuZ2l0aHViLmlvL3BhbG1lcnBlbmd1aW5zLyIpICsKICBmYWNldF93cmFwKHZhcnMoYmlsbF9kaW1lbnNpb24pLAogICAgICAgICAgICAgbGFiZWxsZXIgPSBsYWJlbGxlcihiaWxsX2RpbWVuc2lvbiA9IGRpbV9tbSkpCmBgYAoKIyMgNS4gQWRkIGEgc2Vjb25kIGRpbWVuc2lvbiBvZiBmYWNldGluZyBieSBzcGVjaWVzCmBgYHtyfQpwZW5ndWluc19sb25nICU+JQogIGdncGxvdChhZXMoeCA9IGJvZHlfbWFzc19nLCB5ID0gdmFsdWVfbW0sIGNvbG9yID0gc2V4KSkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfaXBzdW1fcmMoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgbGFicyh4ID0gIkJvZHkgTWFzcyAoZykiLAogICAgICAgeSA9ICJtbSIsCiAgICAgICB0aXRsZSA9ICJCaWxsIGxlbmd0aCBhbmQgZGVwdGggdnMuIGJvZHkgbWFzcyBpbiBwZW5ndWlucyIsCiAgICAgICBjb2xvciA9ICJTZXgiLAogICAgICAgY2FwdGlvbiA9ICJEYXRhIGZyb20gaHR0cHM6Ly9hbGxpc29uaG9yc3QuZ2l0aHViLmlvL3BhbG1lcnBlbmd1aW5zLyIpICsKICBmYWNldF93cmFwKGJpbGxfZGltZW5zaW9ufnNwZWNpZXMsCiAgICAgICAgICAgICBsYWJlbGxlciA9IGxhYmVsbGVyKGJpbGxfZGltZW5zaW9uID0gZGltX21tKSkKYGBgCgojIyA2LiBUYWtlIHlvdXIgcGxvdCBmcm9tIDMgYW5kIGhpZ2hsaWdodApVc2luZyB5b3VyIHBsb3QgZnJvbSBFeGVyY2lzZSAzLCBoaWdobGlnaHQgdGhlIGRhdGFwb2ludHMgY29taW5nIGZyb20gRHJlYW0gSXNsYW5kIGluIHB1cnBsZS4KYGBge3J9CnVuaXF1ZShwZW5ndWluc19sb25nJGlzbGFuZCkKCnBlbmd1aW5zX2xvbmcgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYm9keV9tYXNzX2csIHkgPSB2YWx1ZV9tbSkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gInB1cnBsZSIpICsKICBnZ2hpZ2hsaWdodChpc2xhbmQgPT0gIkRyZWFtIikgKwogIGZhY2V0X3dyYXAodmFycyhiaWxsX2RpbWVuc2lvbikpCmBgYAoKIyMgNy4gSGlnaGxpZ2h0IGxpdHRsZSBwZW5ndWlucwpVc2luZyB5b3VyIHNhbXBsZSBwbG90IGZvciBFeGVyY2lzZSAzLCBoaWdobGlnaHQgcGVuZ3VpbnMgdGhhdCBoYXZlIGEgYGJvZHlfbWFzc19nYCBsZXNzIHRoYW4gMzUwMCBnLCBpbiBibHVlLiAKYGBge3J9CnBlbmd1aW5zX2xvbmcgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYm9keV9tYXNzX2csIHkgPSB2YWx1ZV9tbSkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gImJsdWUiKSArCiAgZ2doaWdobGlnaHQoYm9keV9tYXNzX2cgPCAzNTAwKSArCiAgZmFjZXRfd3JhcCh2YXJzKGJpbGxfZGltZW5zaW9uKSkKYGBgCgojIEJvbnVzIGV4ZXJjaXNlcwojIyAxLiBBbmltYXRpbmcKUGxvdCBgZmxpcHBlcl9sZW5ndGhfbW1gIHZzLiBgYm9keV9tYXNzX2dgIGFuZCBhbmltYXRlIHRoZSBwbG90IHRvIHNob3cgb25seSBvbmUgYHNwZWNpZXNgIGF0IGEgdGltZS4KYGBge3IsIGNhY2hlID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CmZsaXBwZXJfYnlfQlcgPC0gcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYm9keV9tYXNzX2csIHkgPSBmbGlwcGVyX2xlbmd0aF9tbSwgZmlsbCA9IHNwZWNpZXMpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykgKwogIGxhYnModGl0bGUgPSAiUG9wdWxhdGlvbiBhbmQgTGlmZSBFeHBlY3RhbmN5IGluIHRoZSBBbWVyaWNhcyIsCiAgICAgICBzdWJ0aXRsZSA9ICdQZW5ndWluIFNwZWNpZXM6IHtjbG9zZXN0X3N0YXRlfScsIAogICAgICAgeCA9ICJCb2R5IE1hc3MgKGcpIiwgCiAgICAgICB5ID0gIkZsaXBwZXIgTGVuZ3RoIChtbSkiKSArCiAgdHJhbnNpdGlvbl9zdGF0ZXMoc3BlY2llcykgCgphbmltYXRlKGZsaXBwZXJfYnlfQlcpCmBgYAoKIyMgMi4gU2F2ZSB5b3VyIGdpZgpgYGB7ciwgZXZhbCA9IEZBTFNFfQphbmltX3NhdmUoZmlsZW5hbWUgPSAiWU9VUiBGSUxFIFBBVEggSEVSRSIsCiAgICAgICAgICBhbmltYXRpb24gPSBmbGlwcGVyX2J5X0JXKQpgYGAKCiMjIDMuIE11bHRpLXBhbmVsIHBsb3RzCldlIGFyZSBtYWtpbmcgYSBmZXcgcGxvdHMgdG8gYXNzZW1ibGUgYSBtdWx0aS1wYW5lbCBwbG90LiAgTGV0J3MgcmVtZW1iZXIgd2hhdCBkYXRhIHdlJ3JlIHdvcmtpbmcgZm9yLgpgYGB7cn0KaGVhZChwZW5ndWluc19sb25nKQpgYGAKCkJveHBsb3Qgb2YgYGJvZHlfbWFzc19nYCBieSBgc2V4YC4KYGBge3J9CnBlbmd1aW5zX21hc3NfYnlfc2V4IDwtIHBlbmd1aW5zX2xvbmcgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc2V4LCB5ID0gYm9keV9tYXNzX2cpKSArCiAgZ2VvbV9ib3hwbG90KCkKCnBlbmd1aW5zX21hc3NfYnlfc2V4CmBgYAoKSGlzdG9ncmFtIG9mIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgcGVyIGBpc2xhbmRgLgpgYGB7cn0KcGVuZ3VpbnNfYnlfaXNsYW5kIDwtIHBlbmd1aW5zX2xvbmcgJT4lCiAgZ2dwbG90KGFlcyh5ID0gaXNsYW5kLCBmaWxsID0gaXNsYW5kKSkgKwogIGdlb21faGlzdG9ncmFtKHN0YXQgPSAiY291bnQiKQoKcGVuZ3VpbnNfYnlfaXNsYW5kCmBgYApEaXN0cmlidXRpb24gb2YgYGZsaXBwZXJfbGVuZ3RoX21tYCBieSBgc3BlY2llc2AuCmBgYHtyfQpwZW5ndWluc19mbGlwcGVyX3NwZWNpZXMgPC0gcGVuZ3VpbnNfbG9uZyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBmbGlwcGVyX2xlbmd0aF9tbSwgZ3JvdXAgPSBzcGVjaWVzLCBmaWxsID0gc3BlY2llcykpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpCgpwZW5ndWluc19mbGlwcGVyX3NwZWNpZXMKYGBgCgpBc3NlbWJsZSBtdWx0aS1wbG90IGZpZ3VyZSB1c2luZyB0aGUgcGxvdHMgeW91IGp1c3QgbWFkZS4KYGBge3J9CnBlbmd1aW5zX2ZsaXBwZXJfc3BlY2llcyAvIChwZW5ndWluc19tYXNzX2J5X3NleCArIHBlbmd1aW5zX2J5X2lzbGFuZCkgKwogIHBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJMb29raW5nIGF0IHBlbmd1aW5zLi4uIiwKICAgICAgICAgICAgICAgICAgdGFnX2xldmVscyA9ICJBIikKYGBgCgo=